Appearance
P1792 [国家集训队] 种树
题意
一个环上有 Error!。
关键观察
先看直接贪心为什么错:每次取当前美观度最大的位置并ban掉它两侧。 反例 4 7 8 9 中取
反悔贪心的核心(可解任意实数权值,包括负数):
把所有位置放进大根堆,并维护双向链表表示环上的前驱/后继。
每次取出堆顶
(局部最优),累加答案,然后不真正删掉 , 而是把 的左右两点 删除,令 的新权值为 并把
重新压回堆中(链表上 现在夹在 的左边点和 的右边点之间)。 重复
次。
为什么正确:若后续
即
无解判定
环上最多能种 Error!。
实现要点
- 环:
pre[1]=n, nxt[n]=1。 - 堆中保留已删除位置会过期,弹出时用
vis[i]惰性跳过。 - 合并时注意顺序:先取
l = pre[i], r = nxt[i]与被删两点的外层点, 再让i接上pre[l]与nxt[r]。 - 答案用
long long(,绝对值上限约 , 但 long long更稳妥)。
复杂度
时间
费用流版本(sol_mcmf.cpp)
反悔贪心不是凑出来的技巧,它就是下面这个费用流模型的模拟。
建模. 把位置
| 弧 | 容量 | 费用 | 含义 |
|---|---|---|---|
| 1 | 0 | 顶点 | |
| 1 | 图上的边 | ||
| 1 | 0 | 同上 |
路径是二分图(按下标奇偶二染色),所以只连
为什么贪心能
取舍. 显式跑费用流是 sol_mcmf.cpp 与本目录 sol.cpp 在随机对拍中完全一致)。交题请用 sol.cpp。
这题教了什么
"可反悔贪心 / 模拟费用流的退流"这一套想法的模板:用堆做贪心,用链表把"一次选择" 打包成"与它互斥的更优组合"重新投回堆,等价于给贪心一次买后悔药的机会。 与 P1484(线性版本)、BZOJ 1150 数据备份同源,是把交换论证变成数据结构操作的经典手法。